﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MediaRecommender.Model
{
    abstract public class Media : IEquatable<Media>
    {
        static int idcounter;

        #region Fields
        private string _title;
        private uint _id;
        private List<Genre> _genres;
        private Dictionary<string, int> _tags;
        #endregion

        #region Properties
        public string Title
        {
            get { return this._title; }
            private set { this._title = value; }
        }

        public uint ID
        {
            get { return this._id; }
            private set { this._id = value; }
        }

        public List<Genre> Genres
        {
            get { return this._genres; }
            private set { this._genres = value; }
        }

        public Dictionary<string, int> Tags
        {
            get { return this._tags; }
        }
        #endregion

        #region Constructors
        public Media(string title, List<Genre> genres, int genreId)
        {
            this.Title = title;
            this.Genres = genres;
            idcounter++;
            this.ID = ((uint)genreId * 1000000000) + (uint)idcounter;
            this._tags = new Dictionary<string, int>();
        }
        #endregion

        #region Equals
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (this.GetType() != obj.GetType())
                return false;

            return Equals((Media)obj);
        }

        public bool Equals(Media obj)
        {
            if (this.ID == obj.ID)
                return true;

            return false;
        }

        public static bool operator ==(Media leftMedia, Media rightMedia)
        {
            if (ReferenceEquals(leftMedia, null))
                return ReferenceEquals(rightMedia, null);

            return (leftMedia.Equals(rightMedia));
        }

        public static bool operator !=(Media leftMedia, Media rightMedia)
        {
            return !(leftMedia == rightMedia);
        }
        #endregion
    }

    public class Book : Media
    {
        #region Book
        private List<Author> _authors;

        public List<Author> Author 
        {
            get { return this._authors; }
            private set { this._authors = value; } 
        }

        public Book(ICollection<Author> authors, string title, ICollection<Genre> genres)
            : base(title, (List<Genre>)genres, 1)
        {
            this.Author = (List<Author>)authors;

            foreach (var item in authors)
            {
                item.AssociatedMedia.Add(this);
            }
        }
        #endregion
    }

    public class Movie : Media
    {
        #region Movie
        private Director _director;
        private List<Actor> _artist;

        public Director Director
        {
            get { return this._director; }
            private set { this._director = value; }
        }

        public List<Actor> Actors
        {
            get { return this._artist; }
            private set { this._artist = value; }
        }

        public Movie(Director director, ICollection<Actor> actors, string title, ICollection<Genre> genres)
            : base(title, (List<Genre>)genres, 2)
        {
            this.Director = director;
            this.Actors = (List<Actor>)actors;

            director.AssociatedMedia.Add(this);
            foreach (var item in actors)
            {
                item.AssociatedMedia.Add(this);
            }
        }
        #endregion
    }

    public class VideoGame : Media
    {
        #region VideoGame
        private GameStudio _studio;
        private Publisher _publiser;
        private List<Platform> _platforms;

        public GameStudio Studio 
        {
            get { return this._studio; }
            private set { this._studio = value;}
        }

        public Publisher Publiser
        {
            get { return this._publiser; }
            private set { this._publiser = value; }
        }

        public List<Platform> Platforms
        {
            get { return this._platforms; }
            private set { this._platforms = value; }
        }

        public VideoGame(GameStudio studio, Publisher publiser, ICollection<Platform> platforms, string title, ICollection<Genre> genres)
            : base(title, (List<Genre>)genres, 3)
        {
            this.Studio = studio;
            this.Publiser = publiser;
            this.Platforms = (List<Platform>)platforms;

            studio.AssociatedMedia.Add(this);
            publiser.AssociatedMedia.Add(this);
        }
        #endregion
    }
}